﻿#include "timer.h"

static nlist_t timer_list;

#if DBG_DISP_ENABLED(DBG_TIMER_LEVEL)
static void display_timer_list()
{
    plat_printf("--------------timer list-----------------\n");
    nlist_node_t *curr_node;
    int index = 0;
    nlist_for_each(curr_node, &timer_list)
    {
        net_timer_t *timer = nlist_entry(net_timer_t, node, curr_node);
        plat_printf("index:%d name:%s, period:%d, curr:%dms, reload:%dms\n", index++, timer->name, timer->flags, timer->curr, timer->reload);
    }
    plat_printf("-----------------------------------------\n");
}
#else
#define display_timer_list()
#endif

/**
 * @brief 定时器初始化
 */
net_err_t timer_init()
{
    DBG_INFO(DBG_TIMER_LEVEL, "timer init begin!");

    nlist_init(&timer_list);

    DBG_INFO(DBG_TIMER_LEVEL, "timer init end!");
    return NET_ERR_OK;
}

static void insert_timer(net_timer_t *timer)
{
    nlist_node_t *curr_node;

    // 找到插入的位置
    nlist_for_each(curr_node, &timer_list)
    {
        net_timer_t *curr_timer = nlist_entry(net_timer_t, node, curr_node);
        if (timer->curr > curr_timer->curr)
        {
            timer->curr -= curr_timer->curr;
        }
        else if (timer->curr == curr_timer->curr)
        {
            timer->curr = 0;
            nlist_insert_after(&timer_list, &curr_timer->node, &timer->node);
            return;
        }
        else
        {
            // timer->curr < curr_timer->curr;
            curr_timer->curr -= timer->curr;
            nlist_node_t *pre_node = nlist_node_pre(&curr_timer->node);
            if (pre_node)
            {
                nlist_insert_after(&timer_list, pre_node, &timer->node);
            }
            else
            {
                nlist_insert_first(&timer_list, &timer->node);
            }
            return;
        }
    }

    nlist_insert_last(&timer_list, &timer->node);
}

/**
 * @brief 添加定时器
 * @param timer 需要添加的定时器
 * @param name 定时器名称
 * @param proc 定时器调用的函数
 * @param arg 定时器调用函数时传入的参数
 * @param ms 定时器倒计时时间
 * @param flags 是否周期性启用定时器
 */
net_err_t timer_add(net_timer_t *timer, const char *name, timer_proc_t proc, void *arg, int ms, bool flags)
{
    plat_memset(timer->name, 0, TIMER_NAME_SIZE);
    plat_strncpy(timer->name, name, sizeof(name));
    timer->proc = proc;
    timer->arg = arg;
    timer->curr = ms;
    timer->reload = ms;
    timer->flags = flags;
    nlist_node_init(&timer->node);

    insert_timer(timer);
    DBG_INFO(DBG_TIMER_LEVEL, "add timer:%s", timer->name);
    timer->is_added = true;

    display_timer_list();
    return NET_ERR_OK;
}

/**
 * @brief 移除指定的定时器
 */
net_err_t timer_remove(net_timer_t *timer)
{
    // 移除前先判断定时器在不在链表中
    if (!timer->is_added)
    {
        DBG_ERROR(DBG_TIMER_LEVEL, "the timer:%s is not in list!", timer->name);
        return NET_ERR_PARAM;
    }

    DBG_INFO(DBG_TIMER_LEVEL, "remove timer:%s", timer->name);
    nlist_node_t *next_node = nlist_node_next(&timer->node);
    if (next_node)
    {
        net_timer_t *next_timer = nlist_entry(net_timer_t, node, next_node);
        next_timer->curr += timer->curr;
    }
    nlist_remove(&timer_list, &timer->node);
    timer->is_added = false;

    display_timer_list();
    return NET_ERR_OK;
}

/**
 * @brief 扫描并更新定时器时间
 * @param dff_ms 距离上次扫描经过的时间,单位ms
 */
net_err_t timer_check_tmo(int dff_ms)
{
    nlist_t list_wait; // 用于存放到期的定时器，并在稍后进行处理
    nlist_init(&list_wait);

    nlist_node_t *node = nlist_first(&timer_list);
    while (node)
    {
        nlist_node_t *next_node = nlist_node_next(node);
        net_timer_t *curr_timer = nlist_entry(net_timer_t, node, node);

        if (curr_timer->curr > dff_ms)
        {
            curr_timer->curr -= dff_ms;
            break;
        }

        // curr_timer->curr <= dffms
        dff_ms -= curr_timer->curr;
        curr_timer->curr = 0;
        timer_remove(curr_timer);
        nlist_insert_last(&list_wait, node);
        node = next_node;
    }

    while ((node = nlist_remove_first(&list_wait)))
    {
        net_timer_t *timer = nlist_entry(net_timer_t, node, node);
        // 直接这里调用会不会导致定时器等待时间过长？
        timer->proc(timer, timer->arg);
        if (timer->flags == NET_TIMER_RELOAD)
        {
            timer_add(timer, timer->name, timer->proc, timer->arg, timer->reload, timer->flags);
        }
    }

    display_timer_list();
    return NET_ERR_OK;
}

/**
 * @brief 获取第一个定时器的等待时间
 * @return 第一个定时器的等待时间
 */
int timer_first_tmo()
{
    nlist_node_t *node = nlist_first(&timer_list);
    if (node)
    {
        net_timer_t *timer = nlist_entry(net_timer_t, node, node);
        return timer->curr;
    }
    else
    {
        return 0;
    }
}